#include <QtCore/QtEndian>
#include <QtCore/QTimer>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QtSql/QSqlRecord>
#include "smpp/encoders/smpp_binary_encoder.h"
#include "smpp/helpers/smpp_help_func.h"
#include "sessionmanager/session_manager_p.h"
#include "sessionmanager/session_manager.h"
#include "kernel/kernel.h"

namespace smsrouter {

SessionManagerPrivate::SessionManagerPrivate(SessionManager *parent) :
  QObject(0),
  parent(parent),
  src_server(0),
  thread(new QThread(parent)),
  state(STOPED) {
  parent->moveToThread(thread);
  connect(thread, SIGNAL(started()), this, SLOT(threadStarted()));
  connect(this, SIGNAL(sigStop()), this, SLOT(stop()));
  connect(this, SIGNAL(sigResponce(SrcSubmitSm *)),
          this, SLOT(responce(SrcSubmitSm *)));
  connect(this, SIGNAL(sigSend(DestSubmitSm *)),
          this, SLOT(send(DestSubmitSm *)));
  connect(this, SIGNAL(sigSend(SrcDeliverSm *)),
          this, SLOT(send(SrcDeliverSm *)));
}

SessionManagerPrivate::~SessionManagerPrivate() {
  if(thread) {
    delete thread;
    thread = 0;
  }
}

quint32 SessionManagerPrivate::genSrcSequenceNumber(
  smpp::sessions::ServerAsyncSession *session) {
  if(session == 0) {
    return 0;
  }

  quint32 sn(sn_src_sessions.value(session));

  if(sn == 0xFFFFFFFF) {
    sn_src_sessions[session] = 1;
  } else {
    sn_src_sessions[session] = sn + 1;
  }

  return sn;
}

quint32 SessionManagerPrivate::genDestSequenceNumber(
  smpp::sessions::ClientAsyncSession *session) {
  if(session == 0) {
    return 0;
  }

  quint32 sn(sn_dest_sessions.value(session));

  if(sn == 0xFFFFFFFF) {
    sn_dest_sessions[session] = 1;
  } else {
    sn_dest_sessions[session] = sn + 1;
  }

  return sn;
}

void SessionManagerPrivate::threadStarted() {
  src_server = new SourceServer(this);

  connect(src_server, SIGNAL(newSession(int)),
          this, SLOT(newSrc(int)));

  KernelSettings *kernel_settings(Kernel::instance()->settings());

  setState(STARTING);

  if(src_server->listen(kernel_settings->smpp_ip,
                        kernel_settings->smpp_port)) {
    if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
      QMultiHash<int, QVariant> params;
      params.insert(logparam::LOCAL_IP_P, kernel_settings->smpp_ip.toString());
      params.insert(logparam::LOCAL_PORT_P, kernel_settings->smpp_port);

      LogEncoder::instance()->encode(smslog::INFO,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_LISTEN_SRC_SERVER,
                                     params);
    }
  } else {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::LOCAL_IP_P, kernel_settings->smpp_ip.toString());
    params.insert(logparam::LOCAL_PORT_P, kernel_settings->smpp_port);
    params.insert(logparam::ERROR_CODE_P, (int)src_server->serverError());
    params.insert(logparam::ERROR_MSG_P, src_server->errorString());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_NOT_LISTEN_SRC_SERVER,
                                   params);

    setState(ERROR);
    return;
  }

  QList<DestSessionSettings *> dest_sessions(
    Kernel::instance()->getAllDestSessionSettings());

  for(int i = 0; i < dest_sessions.size(); i++) {
    DestSessionSettings *pnt(dest_sessions[i]);
    createDest(pnt->id,
               pnt->ip,
               pnt->port,
               pnt->max_in_speed,
               pnt->max_out_speed,
               pnt->session_init_time,
               pnt->enquire_link_time,
               pnt->inactivity_time,
               pnt->transaction_time,
               pnt->max_in_trans,
               pnt->max_out_trans);
  }

  setState(STARTED);
}

void SessionManagerPrivate::stop() {
  setState(STOPING);
  checkState();
}

void SessionManagerPrivate::newSrc(int socket_descriptor) {
  KernelSettings *kernel_settings(Kernel::instance()->settings());

  createSrc(socket_descriptor,
            kernel_settings->def_max_in_speed,
            kernel_settings->def_max_out_speed,
            kernel_settings->def_session_init_time,
            kernel_settings->def_enquire_link_time,
            kernel_settings->def_inactivity_time,
            kernel_settings->def_transaction_time,
            kernel_settings->def_max_in_trans,
            kernel_settings->def_max_out_trans);
}

void SessionManagerPrivate::openedDest() {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_OPEN_DEST_SESSION,
                                   params);
  }

  DestSessionSettings *dest_sessions_settings(
    Kernel::instance()->getDestSessionSettings(dest_session_id));

  smpp::pdu::BindTransceiver btrx(
    genDestSequenceNumber(session),
    dest_sessions_settings->system_id,
    dest_sessions_settings->password,
    dest_sessions_settings->system_type);

  btrx.setCommandLength(btrx.size());

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << btrx;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransceiver"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_DEST_SESSION,
                                   params);
  }

  session->send(btrx);
}

void SessionManagerPrivate::closedDest() {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_CLOSE_DEST_SESSION,
                                   params);
  }

  if(state == STARTING || state == STARTED) {
    dest_rest_sessions.enqueue(dest_session_id);

    DestSessionSettings *dest_sessions_settings(
      Kernel::instance()->getDestSessionSettings(dest_session_id));

    if(dest_sessions_settings->recovery_time > 0) {
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        QMultiHash<int, QVariant> params;
        params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
        params.insert(logparam::SESS_REC_TIME_P,
                      dest_sessions_settings->recovery_time * 1000);

        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_RESTART_DEST_SESS,
                                       params);
      }

      QTimer::singleShot(dest_sessions_settings->recovery_time * 1000,
                         this, SLOT(restartDest()));
    } else {
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        QMultiHash<int, QVariant> params;
        params.insert(logparam::DEST_SESSION_ID_P,
                      dest_sessions_settings->recovery_time * 1000);

        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_NOT_RESTART_DEST_SESS,
                                       params);
      }
    }
  } else {
    destroyDest(session);
    checkState();
  }
}

void SessionManagerPrivate::restartDest() {
  if(dest_rest_sessions.isEmpty() == false) {
    quint32 dest_session_id(dest_rest_sessions.dequeue());

    DestSessionSettings *dest_session_settings(
      Kernel::instance()->getDestSessionSettings(dest_session_id));

    smpp::sessions::ClientAsyncSession *dest_session =
      dest_sessions.key(dest_session_id, 0);

    if(dest_session && dest_session_settings) {
      dest_session->openSession(dest_session_settings->ip,
                                dest_session_settings->port);
    }
  }
}

void SessionManagerPrivate::errorDest(smpp::sessions::ErrorCode code) {
  smpp::sessions::ClientAsyncSession *dest_session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!dest_session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(dest_session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, dest_session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, dest_session->peerPort());
    params.insert(logparam::LOCAL_IP_P,
                  dest_session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, dest_session->localPort());
    params.insert(logparam::ERROR_CODE_P, (int)code);
    params.insert(logparam::ERROR_MSG_P, dest_session->errorString());

    LogEncoder::instance()->encode(smslog::WARNING,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_ERROR_DEST_SESSION,
                                   params);
  }

  if(code == smpp::sessions::CONN_SOCK_ERR ||
     code == smpp::sessions::DISC_SOCK_ERR) {
    if(state == STARTING || state == STARTED) {
      dest_rest_sessions.enqueue(dest_session_id);

      DestSessionSettings *dest_sessions_settings(
        Kernel::instance()->getDestSessionSettings(dest_session_id));

      if(dest_sessions_settings->recovery_time > 0) {
        if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
          QMultiHash<int, QVariant> params;
          params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
          params.insert(logparam::SESS_REC_TIME_P,
                        dest_sessions_settings->recovery_time * 1000);

          LogEncoder::instance()->encode(smslog::INFO,
                                         logclass::SESSION_MANAGER,
                                         logclass::SESSION_MANAGER,
                                         logmsgcodes::SM_RESTART_DEST_SESS,
                                         params);
        }

        QTimer::singleShot(dest_sessions_settings->recovery_time * 1000,
                           this, SLOT(restartDest()));
      } else if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        QMultiHash<int, QVariant> params;
        params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);

        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_NOT_RESTART_DEST_SESS,
                                       params);
      }
    } else {
      destroyDest(dest_session);
      checkState();
    }
  }
}

void SessionManagerPrivate::send(DestSubmitSm *message) {
  smpp::sessions::ClientAsyncSession *session =
    dest_sessions.key(message->dest_session_id, 0);

  if(session == 0) {
    if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
      smpp::encoders::BinaryEncoder be;
      be << message->sm;
      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("SubmitSM"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, message->dest_session_id);
      params.insert(logparam::ERROR_MSG_P, QString("Not found session"));

      LogEncoder::instance()->encode(smslog::INFO,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_NOT_SEND_DEST_SESSION,
                                     params);
    }
    message->error_code = smpp::parameters::command_status::ESME_RSUBMITFAIL;
    emit parent->responce(message);
    return;
  }

  QList<DestSubmitSm *> *messages = submit_dest_session.value(session, 0);

  if(!messages) {
    if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
      smpp::encoders::BinaryEncoder be;
      be << message->sm;
      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("SubmitSM"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, message->dest_session_id);
      params.insert(logparam::ERROR_MSG_P, QString("Not found message list"));

      LogEncoder::instance()->encode(smslog::INFO,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_NOT_SEND_DEST_SESSION,
                                     params);
    }
    message->error_code = smpp::parameters::command_status::ESME_RSUBMITFAIL;
    emit parent->responce(message);
    return;
  }

  messages->push_back(message);

  message->sm.setSequenceNumber(genDestSequenceNumber(session));

  session->send(message->sm);

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << message->sm;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("SubmitSM"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, message->dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::send(SrcDeliverSm *message) {
  QList<smpp::sessions::ServerAsyncSession *> sessions =
    src_sessions.keys(message->src_session_id);

  if(sessions.isEmpty()) {
    if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
      smpp::encoders::BinaryEncoder be;
      be << message->dm;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
      params.insert(logparam::ERROR_MSG_P, QString("Not found session"));

      LogEncoder::instance()->encode(smslog::INFO,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_NOT_SEND_SRC_SESSION,
                                     params);
    }
    message->error_code =
      smpp::parameters::command_status::ESME_RDELIVERYFAILURE;
    emit parent->responce(message);
    return;
  }

  for(int i = 0; i < sessions.size(); i++) {
    smpp::sessions::ServerAsyncSession *session = sessions[i];
    if(session->state() == smpp::sessions::BOUND_RX ||
       session->state() == smpp::sessions::BOUND_TRX) {
      QList<SrcDeliverSm *> *messages =
        deliver_src_session.value(session, 0);

      if(!messages) {
        if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
          smpp::encoders::BinaryEncoder be;
          be << message->dm;

          QMultiHash<int, QVariant> params;
          params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
          params.insert(logparam::PACKET_DUMP_P, be.getBuff());
          params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
          params.insert(logparam::ERROR_MSG_P, QString("Not found session"));

          LogEncoder::instance()->encode(smslog::INFO,
                                         logclass::SESSION_MANAGER,
                                         logclass::SESSION_MANAGER,
                                         logmsgcodes::SM_NOT_SEND_SRC_SESSION,
                                         params);
        }
        message->error_code =
          smpp::parameters::command_status::ESME_RDELIVERYFAILURE;
        emit parent->responce(message);
        return;
      }

      messages->push_back(message);

      message->dm.setSequenceNumber(genSrcSequenceNumber(session));

      if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
        smpp::encoders::BinaryEncoder be;
        be << message->dm;

        QMultiHash<int, QVariant> params;
        params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
        params.insert(logparam::PACKET_DUMP_P, be.getBuff());
        params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
        params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
        params.insert(logparam::PEER_PORT_P, session->peerPort());
        params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
        params.insert(logparam::LOCAL_PORT_P, session->localPort());

        LogEncoder::instance()->encode(smslog::DEBUG,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_SEND_SRC_SESSION,
                                       params);
      }

      session->send(message->dm);
      return;
    }
  }
  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << message->dm;
    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
    params.insert(logparam::ERROR_MSG_P, QString("Not found session"));

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_NOT_SEND_SRC_SESSION,
                                   params);
  }
  message->error_code =
    smpp::parameters::command_status::ESME_RDELIVERYFAILURE;
  emit parent->responce(message);
}

void SessionManagerPrivate::receiveDest(
  const smpp::pdu::BindTransmitterResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransmitterResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::BindReceiverResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindReceiverResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(
  const smpp::pdu::BindTransceiverResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransceiverResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::UnbindResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("UnbindResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::SubmitSmResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("SubmitSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }

  QList<DestSubmitSm *> *messages =
    submit_dest_session.value(session, 0);

  if(!messages) {
    return;
  }

  DestSessionSettings *dest_sessions_settings(
    Kernel::instance()->getDestSessionSettings(dest_session_id));

  if(!dest_sessions_settings) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    DestSubmitSm *msg = messages->operator [](i);
    if(msg->sm.getSequenceNumber() == p.getSequenceNumber()) {
      msg->error_code = p.getCommandStatus();
      bool ok(true);
      if(dest_sessions_settings->submit_message_id == NUM) {
        msg->dest_message_id = p.getMessageId().toUInt(&ok, 10);
      } else {
        msg->dest_message_id = p.getMessageId().toUInt(&ok, 16);
      }
      messages->removeAt(i);
      emit parent->responce(msg);
      return;
    }
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::DeliverSm &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 dest_session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }

  smpp::pdu::DeliverSmResp deliver_sm_resp(
    smpp::parameters::command_status::ESME_ROK,
    p.getSequenceNumber());

  QList<DestDeliverSm *> *messages = deliver_dest_session.value(session, 0);

  if(!messages) {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_T_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  DestSessionSettings *dest_sessions_settings(
    Kernel::instance()->getDestSessionSettings(dest_session_id));

  if(!dest_sessions_settings) {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_T_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;

      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }

    session->send(deliver_sm_resp);
    return;
  }

  QString short_message(smpp::helpers::fromDataCodes(p.getShortMessage(),
                                                     p.getDataCoding()));

  int pos(dest_sessions_settings->message_id_rule.indexIn(short_message));

  QString message_id_str;

  if(pos > -1) {
    message_id_str = dest_sessions_settings->message_id_rule.cap(1);
  } else {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  pos = dest_sessions_settings->status_rule.indexIn(short_message);

  QString status_str;

  if(pos > -1) {
    status_str = dest_sessions_settings->status_rule.cap(1);
  } else {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  pos = dest_sessions_settings->error_code_rule.indexIn(short_message);

  QString error_code_str;

  if(pos > -1) {
    error_code_str = dest_sessions_settings->error_code_rule.cap(1);
  } else {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  bool ok(false);

  quint32 message_id(0);
  quint32 error_code(error_code_str.toUInt(&ok, 16));
  if(!ok) {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  quint8 status;
  if(status_str == "DELIVRD") {
    status = smpp::parameters::message_state::DELIVERED;
  } else if(status_str == "EXPIRED") {
    status = smpp::parameters::message_state::EXPIRED;
  } else if(status_str == "DELETED") {
    status = smpp::parameters::message_state::DELETED;
  } else if(status_str == "UNDELIV") {
    status = smpp::parameters::message_state::UNDELIVERABLE;
  } else if(status_str == "ACCEPTD") {
    status = smpp::parameters::message_state::ACCEPTED;
  } else if(status_str == "UNKNOWN") {
    status = smpp::parameters::message_state::UNKNOWN;
  } else if(status_str == "REJECTD") {
    status = smpp::parameters::message_state::REJECTED;
  } else {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  if(dest_sessions_settings->deliver_message_id == HEX) {
    message_id = message_id_str.toUInt(&ok, 16);
  } else {
    message_id = message_id_str.toUInt(&ok, 10);
  }
  if(!ok) {
    deliver_sm_resp.setCommandStatus(
      smpp::parameters::command_status::ESME_RX_R_APPN);
    if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
      smpp::encoders::BinaryEncoder be;
      be << deliver_sm_resp;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
      params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
      params.insert(logparam::PEER_PORT_P, session->peerPort());
      params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
      params.insert(logparam::LOCAL_PORT_P, session->localPort());

      LogEncoder::instance()->encode(smslog::WARNING,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_SEND_DEST_SESSION,
                                     params);
    }
    session->send(deliver_sm_resp);
    return;
  }

  DestDeliverSm *message = new DestDeliverSm(dest_session_id,
                                             message_id,
                                             error_code,
                                             status,
                                             p);

  messages->push_back(message);

  emit parent->receive(message);

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << deliver_sm_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, dest_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_DEST_SESSION,
                                   params);
  }

  session->send(deliver_sm_resp);
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::QuerySmResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("QuerySmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::ReplaceSmResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("ReplaceSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::CancelSmResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("CancelSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::EnquireLink &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLink"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }

  smpp::pdu::EnquireLinkResp p_resp(smpp::parameters::command_status::ESME_ROK,
                                    p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLinkResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_DEST_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveDest(const smpp::pdu::EnquireLinkResp &p) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLinkResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_DEST_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::stateChangedDest(smpp::sessions::SessionStates) {

}

void SessionManagerPrivate::sessionInitTimeoutDest() {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    quint32 session_id(dest_sessions.value(session, 0));

    QMultiHash<int, QVariant> params;
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_INIT_DEST_SESSION,
                                   params);
  }

  session->closeSession();
}

void SessionManagerPrivate::enquireLinkTimeoutDest() {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());
  if(!session) {
    return;
  }

  quint32 session_id(dest_sessions.value(session, 0));

  smpp::pdu::EnquireLink p(genDestSequenceNumber(session));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLink"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_DEST_SESSION,
                                   params);
  }

  session->send(p);
}

void SessionManagerPrivate::inactivityTimeoutDest() {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    quint32 session_id(dest_sessions.value(session, 0));

    QMultiHash<int, QVariant> params;
    params.insert(logparam::DEST_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_INACT_DEST_SESSION,
                                   params);
  }

  session->closeSession();
}

void SessionManagerPrivate::outStatusDest(
  const smpp::pdu::Header &header,
  smpp::sessions::StatusMessage status) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  switch(header.getCommandId()) {
    case smpp::parameters::command_id::SUBMIT_SM: {
      switch(status) {
        case smpp::sessions::SESSERROR:
          return outStatusDestSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RSYSERR);
        case smpp::sessions::MAXSPEED:
          return outStatusDestSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RTHROTTLED);
        case smpp::sessions::NOTVALIDSTATE:
          return outStatusDestSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RINVBNDSTS);
        case smpp::sessions::TRANSFULL:
          return outStatusDestSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RMSGQFUL);
        case smpp::sessions::NOTSENDED:
        case smpp::sessions::TRANSTIMEOUT:
          return outStatusDestSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RX_T_APPN);
        default:
          return;
      }
    }
    case smpp::parameters::command_id::DELIVER_SM_RESP: {
      QList<DestDeliverSm *> *messages =
        deliver_dest_session.value(session, 0);

      if(!messages) {
        return;
      }

      for(int i = 0; i < messages->size(); i++) {
        DestDeliverSm *msg = messages->operator [](i);
        if(msg->dm.getSequenceNumber() == header.getSequenceNumber()) {
          messages->removeAt(i);
          switch(status) {
            case smpp::sessions::SENDED:
              emit parent->responced(msg);
              return;
            default:
              delete msg;
              return;
          }
        }
      }
      break;
    }
    case smpp::parameters::command_id::ENQUIRE_LINK: {
      if(status == smpp::sessions::TRANSTIMEOUT) {
        session->closeSession();
      }
      break;
    }
  }
}

void SessionManagerPrivate::inStatusDest(
  const smpp::pdu::Header &header,
  smpp::sessions::StatusMessage status) {
  smpp::sessions::ClientAsyncSession *session =
    qobject_cast<smpp::sessions::ClientAsyncSession *>(sender());

  if(!session) {
    return;
  }

  switch(header.getCommandId()) {
    case smpp::parameters::command_id::DELIVER_SM: {
      switch(status) {
        case smpp::sessions::SESSERROR:
          return inStatusDestDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RSYSERR);
        case smpp::sessions::MAXSPEED:
          return inStatusDestDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RTHROTTLED);
        case smpp::sessions::NOTVALIDSTATE:
          return inStatusDestDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RINVBNDSTS);
        case smpp::sessions::TRANSFULL:
          return inStatusDestDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RMSGQFUL);
        case smpp::sessions::NOTSENDED:
        case smpp::sessions::TRANSTIMEOUT:
          return inStatusDestDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RX_T_APPN);
        default:
          return;
      }
    }
    case smpp::parameters::command_id::ENQUIRE_LINK: {
      if(status == smpp::sessions::TRANSTIMEOUT) {
        session->closeSession();
      }
      break;
    }
  }
}

void SessionManagerPrivate::openedSrc() {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_OPEN_SRC_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::closedSrc() {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 src_session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::SRC_SESSION_ID_P, src_session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_CLOSE_SRC_SESSION,
                                   params);
  }

  destroySrc(session);

  checkState();
}

void SessionManagerPrivate::responce(SrcSubmitSm *message) {
  smpp::pdu::SubmitSmResp p(message->error_code,
                            message->sm.getSequenceNumber(),
                            QString::number(message->src_message_id));

  p.setCommandLength(p.size());

  QList<smpp::sessions::ServerAsyncSession *> sessions(
    src_sessions.keys(message->src_session_id));

  for(int i = 0; i < sessions.size(); i++) {
    smpp::sessions::ServerAsyncSession *session(sessions[i]);

    QList<SrcSubmitSm *> *messages =
      submit_src_session.value(session, 0);

    if(!messages) {
      continue;
    }

    if(messages->contains(message)) {
      messages->removeAll(message);

      messages = submit_resp_src_session.value(session, 0);

      if(!messages) {
        continue;
      }

      messages->push_back(message);

      if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
        smpp::encoders::BinaryEncoder be;
        be << p;

        QMultiHash<int, QVariant> params;
        params.insert(logparam::PACKET_TYPE_P, QString("SubmitSmResp"));
        params.insert(logparam::PACKET_DUMP_P, be.getBuff());
        params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
        params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
        params.insert(logparam::PEER_PORT_P, session->peerPort());
        params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
        params.insert(logparam::LOCAL_PORT_P, session->localPort());

        LogEncoder::instance()->encode(smslog::DEBUG,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_SEND_SRC_SESSION,
                                       params);
      }

      session->send(p);

      return;
    }
  }

  if(submit_src_error.contains(message)) {
    message->message_state =
      smpp::parameters::message_state::UNDELIVERABLE;

    message->error_code = submit_src_error.take(message);
  } else {
    message->message_state =
      smpp::parameters::message_state::UNDELIVERABLE;
    message->error_code =
      smpp::parameters::command_status::ESME_RSUBMITFAIL;

    if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
      smpp::encoders::BinaryEncoder be;
      be << p;

      QMultiHash<int, QVariant> params;
      params.insert(logparam::PACKET_TYPE_P, QString("SubmitSmResp"));
      params.insert(logparam::PACKET_DUMP_P, be.getBuff());
      params.insert(logparam::SRC_SESSION_ID_P, message->src_session_id);
      params.insert(logparam::ERROR_MSG_P, QString("Not found session"));

      LogEncoder::instance()->encode(smslog::INFO,
                                     logclass::SESSION_MANAGER,
                                     logclass::SESSION_MANAGER,
                                     logmsgcodes::SM_NOT_SEND_SRC_SESSION,
                                     params);
    }
  }

  emit parent->responced(message);
}

void SessionManagerPrivate::errorSrc(smpp::sessions::ErrorCode code) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() >= smslog::WARNING) {
    QMultiHash<int, QVariant> params;
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());
    params.insert(logparam::ERROR_CODE_P, (int)code);
    params.insert(logparam::ERROR_MSG_P, session->errorString());

    LogEncoder::instance()->encode(smslog::WARNING,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_ERROR_SRC_SESSION,
                                   params);
  }

  if(code == smpp::sessions::DISC_SOCK_ERR) {
    destroySrc(session);
    checkState();
  }
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::BindTransmitter &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransmitter"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, 0);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  quint32 command_status(smpp::parameters::command_status::ESME_ROK);

  quint32 src_session_id(Kernel::instance()->authSrcSession(p.getSystemId(),
                                                            p.getPassword(),
                                                            &command_status));

  if(src_session_id != 0) {
    QList<smpp::sessions::ServerAsyncSession *> sessions(
      src_sessions.keys(src_session_id));
    for(int i = 0; i < sessions.size(); i++) {
      smpp::sessions::ServerAsyncSession *session(sessions[i]);
      if(session->state() == smpp::sessions::BOUND_TX) {
        command_status = smpp::parameters::command_status::ESME_RALYBND;
        break;
      }
    }
  }

  if(command_status == smpp::parameters::command_status::ESME_ROK) {
    SrcSessionSettings *pnt(
      Kernel::instance()->getSrcSessionSettings(src_session_id));

    session->setMaxInSpeed(pnt->max_in_speed);
    session->setMaxOutSpeed(pnt->max_out_speed);
    session->setSessionInitTime(pnt->session_init_time);
    session->setEnquireLinkTime(pnt->enquire_link_time);
    session->setInactivityTime(pnt->inactivity_time);
    session->setTransactionTime(pnt->transaction_time);
    session->setMaxInTrans(pnt->max_in_trans);
    session->setMaxOutTrans(pnt->max_out_trans);

    src_sessions.insert(session, src_session_id);
  }

  smpp::pdu::BindTransmitterResp p_resp(command_status,
                                        p.getSequenceNumber(),
                                        p.getSystemId());

  p_resp.setCommandLength(p_resp.size());

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransmitterResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, src_session_id);
    params.insert(logparam::PEER_IP_P,
                  session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P,
                  session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::BindReceiver &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindReceiver"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, 0);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  quint32 command_status(smpp::parameters::command_status::ESME_ROK);

  quint32 src_session_id(Kernel::instance()->authSrcSession(p.getSystemId(),
                                                            p.getPassword(),
                                                            &command_status));

  if(src_session_id != 0) {
    QList<smpp::sessions::ServerAsyncSession *> sessions(
      src_sessions.keys(src_session_id));
    for(int i = 0; i < sessions.size(); i++) {
      smpp::sessions::ServerAsyncSession *session(sessions[i]);
      if(session->state() == smpp::sessions::BOUND_RX) {
        command_status = smpp::parameters::command_status::ESME_RALYBND;
        break;
      }
    }
  }

  if(command_status == smpp::parameters::command_status::ESME_ROK) {
    SrcSessionSettings *pnt(
      Kernel::instance()->getSrcSessionSettings(src_session_id));

    session->setMaxInSpeed(pnt->max_in_speed);
    session->setMaxOutSpeed(pnt->max_out_speed);
    session->setSessionInitTime(pnt->session_init_time);
    session->setEnquireLinkTime(pnt->enquire_link_time);
    session->setInactivityTime(pnt->inactivity_time);
    session->setTransactionTime(pnt->transaction_time);
    session->setMaxInTrans(pnt->max_in_trans);
    session->setMaxOutTrans(pnt->max_out_trans);

    src_sessions.insert(session, src_session_id);
  }

  smpp::pdu::BindReceiverResp p_resp(command_status,
                                     p.getSequenceNumber(),
                                     p.getSystemId());

  p_resp.setCommandLength(p_resp.size());

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindReceiverResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, src_session_id);
    params.insert(logparam::PEER_IP_P,
                  session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P,
                  session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::BindTransceiver &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransceiver"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, 0);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  quint32 command_status(smpp::parameters::command_status::ESME_ROK);

  quint32 src_session_id(Kernel::instance()->authSrcSession(p.getSystemId(),
                                                            p.getPassword(),
                                                            &command_status));

  if(src_session_id != 0) {
    QList<smpp::sessions::ServerAsyncSession *> sessions(
      src_sessions.keys(src_session_id));
    for(int i = 0; i < sessions.size(); i++) {
      smpp::sessions::ServerAsyncSession *session(sessions[i]);
      if(session->state() == smpp::sessions::BOUND_TRX) {
        command_status = smpp::parameters::command_status::ESME_RALYBND;
        break;
      }
    }
  }

  if(command_status == smpp::parameters::command_status::ESME_ROK) {
    SrcSessionSettings *pnt(
      Kernel::instance()->getSrcSessionSettings(src_session_id));

    session->setMaxInSpeed(pnt->max_in_speed);
    session->setMaxOutSpeed(pnt->max_out_speed);
    session->setSessionInitTime(pnt->session_init_time);
    session->setEnquireLinkTime(pnt->enquire_link_time);
    session->setInactivityTime(pnt->inactivity_time);
    session->setTransactionTime(pnt->transaction_time);
    session->setMaxInTrans(pnt->max_in_trans);
    session->setMaxOutTrans(pnt->max_out_trans);

    src_sessions.insert(session, src_session_id);
  }

  smpp::pdu::BindTransceiverResp p_resp(command_status,
                                        p.getSequenceNumber(),
                                        p.getSystemId());

  p_resp.setCommandLength(p_resp.size());

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("BindTransceiverResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, src_session_id);
    params.insert(logparam::PEER_IP_P,
                  session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P,
                  session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::Unbind &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("Unbind"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  if(p.getCommandStatus() == smpp::parameters::command_status::ESME_ROK) {
    src_sessions.remove(session);
  }

  smpp::pdu::UnbindResp p_resp(smpp::parameters::command_status::ESME_ROK,
                               p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("UnbindResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::SubmitSm &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("SubmitSm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  QList<SrcSubmitSm *> *messages = submit_src_session.value(session, 0);

  if(!messages) {
    return;
  }

  SrcSubmitSm *msg = new SrcSubmitSm(session_id,
                                     Kernel::instance()->genMessageId(),
                                     p);

  messages->push_back(msg);

  emit parent->receive(msg);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::DeliverSmResp &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("DeliverSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  QList<SrcDeliverSm *> *messages = deliver_src_session.value(session, 0);

  if(!messages) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    SrcDeliverSm *msg = messages->operator [](i);
    if(msg->dm.getSequenceNumber() == p.getSequenceNumber()) {
      msg->error_code = p.getCommandStatus();
      messages->removeAt(i);
      emit parent->responce(msg);
      return;
    }
  }
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::QuerySm &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("QuerySm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  smpp::pdu::QuerySmResp p_resp(
    smpp::parameters::command_status::ESME_RQUERYFAIL,
    p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("QuerySmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::ReplaceSm &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("ReplaceSm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  smpp::pdu::ReplaceSmResp p_resp(
    smpp::parameters::command_status::ESME_RQUERYFAIL,
    p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("ReplaceSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::CancelSm &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("CancelSm"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  smpp::pdu::CancelSmResp p_resp(
    smpp::parameters::command_status::ESME_RQUERYFAIL,
    p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("CancelSmResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::EnquireLink &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLink"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }

  smpp::pdu::EnquireLinkResp p_resp(smpp::parameters::command_status::ESME_ROK,
                                    p.getSequenceNumber());

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p_resp;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLinkResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p_resp);
}

void SessionManagerPrivate::receiveSrc(const smpp::pdu::EnquireLinkResp &p) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLinkResp"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_RECEIVE_SRC_SESSION,
                                   params);
  }
}

void SessionManagerPrivate::stateChangedSrc(smpp::sessions::SessionStates) {

}

void SessionManagerPrivate::sessionInitTimeoutSrc() {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    quint32 session_id(src_sessions.value(session, 0));

    QMultiHash<int, QVariant> params;
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_INIT_SRC_SESSION,
                                   params);
  }

  session->closeSession();
}

void SessionManagerPrivate::enquireLinkTimeoutSrc() {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  quint32 session_id(src_sessions.value(session, 0));

  smpp::pdu::EnquireLink p(genSrcSequenceNumber(session));

  if(Kernel::instance()->getLogLevel() == smslog::DEBUG) {
    smpp::encoders::BinaryEncoder be;
    be << p;

    QMultiHash<int, QVariant> params;
    params.insert(logparam::PACKET_TYPE_P, QString("EnquireLink"));
    params.insert(logparam::PACKET_DUMP_P, be.getBuff());
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::DEBUG,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_SEND_SRC_SESSION,
                                   params);
  }

  session->send(p);
}

void SessionManagerPrivate::inactivityTimeoutSrc() {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
    quint32 session_id(src_sessions.value(session, 0));

    QMultiHash<int, QVariant> params;
    params.insert(logparam::SRC_SESSION_ID_P, session_id);
    params.insert(logparam::PEER_IP_P, session->peerAddress().toString());
    params.insert(logparam::PEER_PORT_P, session->peerPort());
    params.insert(logparam::LOCAL_IP_P, session->localAddress().toString());
    params.insert(logparam::LOCAL_PORT_P, session->localPort());

    LogEncoder::instance()->encode(smslog::INFO,
                                   logclass::SESSION_MANAGER,
                                   logclass::SESSION_MANAGER,
                                   logmsgcodes::SM_INACT_SRC_SESSION,
                                   params);
  }

  session->closeSession();
}

void SessionManagerPrivate::outStatusSrc(
  const smpp::pdu::Header &header,
  smpp::sessions::StatusMessage status) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  switch(header.getCommandId()) {
    case smpp::parameters::command_id::DELIVER_SM: {
      switch(status) {
        case smpp::sessions::SENDED:
        case smpp::sessions::TRANSSTART:
        case smpp::sessions::RESPONSED:
          return;
        case smpp::sessions::SESSERROR:
          return outStatusSrcDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RSYSERR);
        case smpp::sessions::MAXSPEED:
          return outStatusSrcDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RTHROTTLED);
        case smpp::sessions::NOTVALIDSTATE:
          return outStatusSrcDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RINVBNDSTS);
        case smpp::sessions::TRANSFULL:
          return outStatusSrcDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RMSGQFUL);
        case smpp::sessions::TRANSTIMEOUT:
        case smpp::sessions::NOTSENDED:
        default:
          return outStatusSrcDeliverSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RX_T_APPN);
      }
    }
    case smpp::parameters::command_id::SUBMIT_SM_RESP: {
      QList<SrcSubmitSm *> *messages =
        submit_resp_src_session.value(session, 0);

      if(!messages) {
        return;
      }

      for(int i = 0; i < messages->size(); i++) {
        SrcSubmitSm *msg = messages->operator [](i);
        if(msg->sm.getSequenceNumber() ==
           header.getSequenceNumber()) {
          messages->removeAt(i);
          switch(status) {
            case smpp::sessions::NOTSENDED:
              msg->message_state =
                smpp::parameters::message_state::UNDELIVERABLE;
              msg->error_code =
                smpp::parameters::command_status::ESME_RX_T_APPN;
              break;
            default:
              break;
          }
          emit parent->responced(msg);
          break;
        }
      }
      break;
    }
    case smpp::parameters::command_id::ENQUIRE_LINK: {
      if(status == smpp::sessions::TRANSTIMEOUT) {
        session->closeSession();
      }
      break;
    }
  }
}

void SessionManagerPrivate::inStatusSrc(
  const smpp::pdu::Header &header,
  smpp::sessions::StatusMessage status) {
  smpp::sessions::ServerAsyncSession *session =
    qobject_cast<smpp::sessions::ServerAsyncSession *>(sender());

  if(!session) {
    return;
  }

  switch(header.getCommandId()) {
    case smpp::parameters::command_id::SUBMIT_SM: {
      switch(status) {
        case smpp::sessions::SENDED:
        case smpp::sessions::TRANSSTART:
        case smpp::sessions::RESPONSED:
          return;
        case smpp::sessions::SESSERROR:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RSYSERR);
        case smpp::sessions::NOTSENDED:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RSUBMITFAIL);
        case smpp::sessions::MAXSPEED:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RTHROTTLED);
        case smpp::sessions::NOTVALIDSTATE:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RINVBNDSTS);
        case smpp::sessions::TRANSFULL:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RMSGQFUL);
        case smpp::sessions::TRANSTIMEOUT:
        default:
          return inStatusSrcSubmitSm(
            header,
            session,
            smpp::parameters::command_status::ESME_RDELIVERYFAILURE);
      }
    }
    case smpp::parameters::command_id::ENQUIRE_LINK: {
      if(status == smpp::sessions::TRANSTIMEOUT) {
        session->closeSession();
      }
      break;
    }
  }
}

void SessionManagerPrivate::createSrc(int sock_desc,
                                      int in_speed, // msec
                                      int out_speed, // msec
                                      int session_init_time,
                                      int enquire_link_time,
                                      int inactivity_time,
                                      int transaction_time,
                                      int max_in_trans,
                                      int max_out_trans) {
  smpp::sessions::ServerAsyncSession *session(
    new smpp::sessions::ServerAsyncSession(sock_desc,
                                           in_speed,
                                           out_speed,
                                           session_init_time,
                                           enquire_link_time,
                                           inactivity_time,
                                           transaction_time,
                                           max_in_trans,
                                           max_out_trans));

  connect(session, SIGNAL(error(smpp::sessions::ErrorCode)),
          this, SLOT(errorSrc(smpp::sessions::ErrorCode)));
  connect(session, SIGNAL(openedSession()),
          this, SLOT(openedSrc()));
  connect(session, SIGNAL(closedSession()),
          this, SLOT(closedSrc()));
  connect(session, SIGNAL(receive(const smpp::pdu::BindTransmitter &)),
          this, SLOT(receiveSrc(const smpp::pdu::BindTransmitter &)));
  connect(session, SIGNAL(receive(const smpp::pdu::BindReceiver &)),
          this, SLOT(receiveSrc(const smpp::pdu::BindReceiver &)));
  connect(session, SIGNAL(receive(const smpp::pdu::BindTransceiver &)),
          this, SLOT(receiveSrc(const smpp::pdu::BindTransceiver &)));
  connect(session, SIGNAL(receive(const smpp::pdu::Unbind &)),
          this, SLOT(receiveSrc(const smpp::pdu::Unbind &)));
  connect(session, SIGNAL(receive(const smpp::pdu::SubmitSm &)),
          this, SLOT(receiveSrc(const smpp::pdu::SubmitSm &)));
  connect(session, SIGNAL(receive(const smpp::pdu::DeliverSmResp &)),
          this, SLOT(receiveSrc(const smpp::pdu::DeliverSmResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::QuerySm &)),
          this, SLOT(receiveSrc(const smpp::pdu::QuerySm &)));
  connect(session, SIGNAL(receive(const smpp::pdu::ReplaceSm &)),
          this, SLOT(receiveSrc(const smpp::pdu::ReplaceSm &)));
  connect(session, SIGNAL(receive(const smpp::pdu::CancelSm &)),
          this, SLOT(receiveSrc(const smpp::pdu::CancelSm &)));
  connect(session, SIGNAL(receive(const smpp::pdu::EnquireLink &)),
          this, SLOT(receiveSrc(const smpp::pdu::EnquireLink &)));
  connect(session, SIGNAL(receive(const smpp::pdu::EnquireLinkResp &)),
          this, SLOT(receiveSrc(const smpp::pdu::EnquireLinkResp &)));
  connect(session, SIGNAL(inStatus(const smpp::pdu::Header &,
                                   smpp::sessions::StatusMessage)),
          this, SLOT(inStatusSrc(const smpp::pdu::Header &,
                                 smpp::sessions::StatusMessage)));
  connect(session, SIGNAL(outStatus(const smpp::pdu::Header &,
                                    smpp::sessions::StatusMessage)),
          this, SLOT(outStatusSrc(const smpp::pdu::Header &,
                                  smpp::sessions::StatusMessage)));
  connect(session, SIGNAL(stateChanged(smpp::sessions::SessionStates)),
          this, SLOT(stateChangedSrc(smpp::sessions::SessionStates)));
  connect(session, SIGNAL(sessionInitTimeout()),
          this, SLOT(sessionInitTimeoutSrc()));
  connect(session, SIGNAL(enquireLinkTimeout()),
          this, SLOT(enquireLinkTimeoutSrc()));
  connect(session, SIGNAL(inactivityTimeout()),
          this, SLOT(inactivityTimeoutSrc()));

  sn_src_sessions.insert(session, 1);
  submit_src_session.insert(session, new QList<SrcSubmitSm *>);
  submit_resp_src_session.insert(session, new QList<SrcSubmitSm *>);
  deliver_src_session.insert(session, new QList<SrcDeliverSm *>);
}

void SessionManagerPrivate::createDest(quint32 dest_session_id,
                                       const QHostAddress &addr,
                                       quint16 port,
                                       int max_in_speed, // msec
                                       int max_out_speed, // msec
                                       int session_init_time,
                                       int enquire_link_time,
                                       int inactivity_time,
                                       int transaction_time,
                                       int max_in_trans,
                                       int max_out_trans) {
  smpp::sessions::ClientAsyncSession *session(
    new smpp::sessions::ClientAsyncSession(
      max_in_speed,
      max_out_speed,
      session_init_time,
      enquire_link_time,
      inactivity_time,
      transaction_time,
      max_in_trans,
      max_out_trans));

  connect(session, SIGNAL(openedSession()),
          this, SLOT(openedDest()));
  connect(session, SIGNAL(closedSession()),
          this, SLOT(closedDest()));
  connect(session, SIGNAL(error(smpp::sessions::ErrorCode)),
          this, SLOT(errorDest(smpp::sessions::ErrorCode)));
  connect(session, SIGNAL(receive(const smpp::pdu::BindTransmitterResp &)),
          this, SLOT(receiveDest(const smpp::pdu::BindTransmitterResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::BindReceiverResp &)),
          this, SLOT(receiveDest(const smpp::pdu::BindReceiverResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::BindTransceiverResp &)),
          this, SLOT(receiveDest(const smpp::pdu::BindTransceiverResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::UnbindResp &)),
          this, SLOT(receiveDest(const smpp::pdu::UnbindResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::SubmitSmResp &)),
          this, SLOT(receiveDest(const smpp::pdu::SubmitSmResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::DeliverSm &)),
          this, SLOT(receiveDest(const smpp::pdu::DeliverSm &)));
  connect(session, SIGNAL(receive(const smpp::pdu::QuerySmResp &)),
          this, SLOT(receiveDest(const smpp::pdu::QuerySmResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::ReplaceSmResp &)),
          this, SLOT(receiveDest(const smpp::pdu::ReplaceSmResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::CancelSmResp &)),
          this, SLOT(receiveDest(const smpp::pdu::CancelSmResp &)));
  connect(session, SIGNAL(receive(const smpp::pdu::EnquireLink &)),
          this, SLOT(receiveDest(const smpp::pdu::EnquireLink &)));
  connect(session, SIGNAL(receive(const smpp::pdu::EnquireLinkResp &)),
          this, SLOT(receiveDest(const smpp::pdu::EnquireLinkResp &)));
  connect(session, SIGNAL(inStatus(const smpp::pdu::Header &,
                                   smpp::sessions::StatusMessage)),
          this, SLOT(inStatusDest(const smpp::pdu::Header &,
                                  smpp::sessions::StatusMessage)));
  connect(session, SIGNAL(outStatus(const smpp::pdu::Header &,
                                    smpp::sessions::StatusMessage)),
          this, SLOT(outStatusDest(const smpp::pdu::Header &,
                                   smpp::sessions::StatusMessage)));
  connect(session, SIGNAL(stateChanged(smpp::sessions::SessionStates)),
          this, SLOT(stateChangedDest(smpp::sessions::SessionStates)));
  connect(session, SIGNAL(sessionInitTimeout()),
          this, SLOT(sessionInitTimeoutDest()));
  connect(session, SIGNAL(enquireLinkTimeout()),
          this, SLOT(enquireLinkTimeoutDest()));
  connect(session, SIGNAL(inactivityTimeout()),
          this, SLOT(inactivityTimeoutDest()));

  sn_dest_sessions.insert(session, 1);

  dest_sessions.insert(session, dest_session_id);

  submit_dest_session.insert(session, new QList<DestSubmitSm *>);

  deliver_dest_session.insert(session, new QList<DestDeliverSm *>);

  session->openSession(QHostAddress(addr), port);
}

void SessionManagerPrivate::destroySrc(
  smpp::sessions::ServerAsyncSession *session) {
  sn_src_sessions.remove(session);
  src_sessions.remove(session);

  QList<SrcSubmitSm *> *submit_messages =
    submit_src_session.value(session, 0);

  if(submit_messages) {
    submit_src_session.remove(session);
    delete submit_messages;
  }

  QList<SrcSubmitSm *> *submit_resp_messages =
    submit_resp_src_session.value(session, 0);

  if(submit_resp_messages) {
    submit_resp_src_session.remove(session);
    delete submit_resp_messages;
  }

  QList<SrcDeliverSm *> *deliver_messages =
    deliver_src_session.value(session, 0);

  if(deliver_messages) {
    deliver_src_session.remove(session);
    delete deliver_messages;
  }

  delete session;
}

void SessionManagerPrivate::destroyDest(
  smpp::sessions::ClientAsyncSession *session) {
  sn_dest_sessions.remove(session);
  dest_sessions.remove(session);

  QList<DestSubmitSm *> *submit_messages =
    submit_dest_session.value(session, 0);

  if(submit_messages) {
    submit_dest_session.remove(session);
    delete submit_messages;
  }

  QList<DestDeliverSm *> *deliver_messages =
    deliver_dest_session.value(session, 0);

  if(deliver_messages) {
    deliver_dest_session.remove(session);
    delete deliver_messages;
  }

  delete session;
}

void SessionManagerPrivate::inStatusSrcSubmitSm(
  const smpp::pdu::Header &header,
  smpp::sessions::ServerAsyncSession *session,
  quint32 error_code) {
  QList<SrcSubmitSm *> *messages = submit_src_session.value(session, 0);

  if(!messages) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    SrcSubmitSm *msg = messages->operator [](i);
    if(msg->sm.getSequenceNumber() == header.getSequenceNumber()) {
      messages->removeAt(i);
      submit_src_error.insert(msg, error_code);
    }
  }
}

void SessionManagerPrivate::outStatusSrcDeliverSm(
  const smpp::pdu::Header &header,
  smpp::sessions::ServerAsyncSession *session,
  quint32 error_code) {
  QList<SrcDeliverSm *> *messages = deliver_src_session.value(session, 0);

  if(!messages) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    SrcDeliverSm *msg = messages->operator [](i);
    if(msg->dm.getSequenceNumber() == header.getSequenceNumber()) {
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        smpp::encoders::BinaryEncoder be;
        be << msg->dm;

        QMultiHash<int, QVariant> params;
        params.insert(logparam::PACKET_TYPE_P, QString("DeliverSm"));
        params.insert(logparam::PACKET_DUMP_P, be.getBuff());
        params.insert(logparam::SRC_SESSION_ID_P, msg->src_session_id);
        params.insert(logparam::ERROR_MSG_P,
                      QString("Error session code (%1)").arg(error_code));

        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_NOT_SEND_SRC_SESSION,
                                       params);
      }

      msg->error_code = error_code;
      messages->removeAt(i);
      emit parent->responce(msg);
    }
  }
}

void SessionManagerPrivate::outStatusDestSubmitSm(
  const smpp::pdu::Header &header,
  smpp::sessions::ClientAsyncSession *session,
  quint32 error_code) {
  QList<DestSubmitSm *> *messages = submit_dest_session.value(session, 0);

  if(!messages) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    DestSubmitSm *msg = messages->operator [](i);
    if(msg->sm.getSequenceNumber() == header.getSequenceNumber()) {
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        smpp::encoders::BinaryEncoder be;
        be << msg->sm;
        QMultiHash<int, QVariant> params;
        params.insert(logparam::PACKET_TYPE_P, QString("SubmitSM"));
        params.insert(logparam::PACKET_DUMP_P, be.getBuff());
        params.insert(logparam::DEST_SESSION_ID_P, msg->dest_session_id);
        params.insert(logparam::ERROR_MSG_P,
                      QString("Error session code(%1)").arg(error_code));

        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_NOT_SEND_DEST_SESSION,
                                       params);
      }

      msg->error_code = error_code;
      messages->removeAt(i);
      emit parent->responce(msg);
      return;
    }
  }
}

void SessionManagerPrivate::inStatusDestDeliverSm(
  const smpp::pdu::Header &header,
  smpp::sessions::ClientAsyncSession *session,
  quint32 error_code) {
  QList<DestDeliverSm *> *messages = deliver_dest_session.value(session, 0);

  if(!messages) {
    return;
  }

  for(int i = 0; i < messages->size(); i++) {
    DestDeliverSm *msg = messages->operator [](i);
    if(msg->dm.getSequenceNumber() == header.getSequenceNumber()) {
      msg->error_code = error_code;
      messages->removeAt(i);
      emit parent->responced(msg);
      return;
    }
  }
}

QString SessionManagerPrivate::stateToString(
  smpp::sessions::SessionStates state) const {
  switch(state) {
    case smpp::sessions::OPEN:
      return QString("OPEN");
    case smpp::sessions::BOUND_TX:
      return QString("BOUND_TX");
    case smpp::sessions::BOUND_RX:
      return QString("BOUND_RX");
    case smpp::sessions::BOUND_TRX:
      return QString("BOUND_TRX");
    case smpp::sessions::UNBOUND:
      return QString("UNBOUND");
    case smpp::sessions::OUTBOUND:
      return QString("OUTBOUND");
    default:
      return QString("CLOSED");
  }
}

void SessionManagerPrivate::checkState() {
  switch(state) {
    case STOPING:
      if(dest_sessions.isEmpty()) {
        setState(STOPED);
      }
      break;
    default:
      break;
  }
}

void SessionManagerPrivate::setState(State state) {
  if(this->state == state)
    return;

  switch(state) {
    case ERROR:
      if(state == STOPING) {
        return;
      } else if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_ERROR_STATE);
      }
      break;
    case STOPING:
      if(state == STOPED) {
        return;
      } else {
        src_server->close();
        for(QHash<smpp::sessions::ServerAsyncSession *, quint32>::iterator i =
              src_sessions.begin();
            i != src_sessions.end();
            i++) {
          smpp::sessions::ServerAsyncSession *session(i.key());
          session->closeSession();
        }
        for(QHash<smpp::sessions::ClientAsyncSession *, quint32>::iterator i =
              dest_sessions.begin();
            i != dest_sessions.end();
            i++) {
          smpp::sessions::ClientAsyncSession *session(i.key());
          session->closeSession();
        }

        if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
          LogEncoder::instance()->encode(smslog::INFO,
                                         logclass::SESSION_MANAGER,
                                         logclass::SESSION_MANAGER,
                                         logmsgcodes::SM_STOPING_STATE);
        }
      }
      break;
    case STARTING:
      if(state == STARTED) {
        return;
      } else {
        if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
          LogEncoder::instance()->encode(smslog::INFO,
                                         logclass::SESSION_MANAGER,
                                         logclass::SESSION_MANAGER,
                                         logmsgcodes::SM_STARTING_STATE);
        }
      }
      break;
    case STARTED:
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_STARTED_STATE);
      }
      break;
    case STOPED:
      if(Kernel::instance()->getLogLevel() >= smslog::INFO) {
        LogEncoder::instance()->encode(smslog::INFO,
                                       logclass::SESSION_MANAGER,
                                       logclass::SESSION_MANAGER,
                                       logmsgcodes::SM_STOPED_STATE);
      }
      break;
  }

  this->state = state;

  emit parent->stateChanged(state);
}

SessionManager::SessionManager() :
  QObject(0), p(new SessionManagerPrivate(this)) {

}

SessionManager::~SessionManager() {
  if(p) {
    if(p->thread) {
      if(p->thread->isRunning()) {
        p->thread->quit();
        p->thread->wait();
      }
    }
    delete p;
    p = 0;
  }
}

State SessionManager::getState() {
  return p->state;
}

void SessionManager::start() {
  p->thread->start();
}

void SessionManager::stop() {
  emit p->sigStop();
}

void SessionManager::responce(SrcSubmitSm *message) {
  emit p->sigResponce(message);
}

void SessionManager::send(DestSubmitSm *message) {
  emit p->sigSend(message);
}

void SessionManager::send(SrcDeliverSm *message) {
  emit p->sigSend(message);
}

} // namespace smsrouter
